<?php
/*
Plugin Name: MG Auto nofollow
Plugin URI: http://www.bymg.com/wordpress-plugins/mg-auto-nofollow
Description: 为博客上所有链接增加rel="nofollow"标签，并允许在后台设定生效的网址范围
Version: 0.0.1
Author: Mike Gaul
Author URI: http://www.bymg.com
*/

if(preg_match('#'.basename(__FILE__).'#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }

if(!defined('MG_AUTO_NOFOLLOW_ABSPATH')) define('MG_AUTO_NOFOLLOW_ABSPATH', ABSPATH.'/'.PLUGINDIR.'/mg-auto-nofollow' );

class mgPlugin_AutoNoFollow {
    
    var $options = array();
    
    var $labels = array();
    
    function mgPlugin_AutoNoFollow()
    {
        $this->options = get_option('mg_auto_nofollow');
        
        // 设定作用范围的默认值
        if (empty($this->options['effective_on'])) {
            $this->options['effective_on'] = 'the_content';
        }
        // 设定生效方法的默认值
        if (empty($this->options['the_way'])) {
            $this->options['the_way'] = 'rel';
        }
        // 使用黑白名单
        if (empty($this->options['use_list'])) {
            $this->options['use_list'] = 'none';
        }
        if (empty($this->options['black_list'])) {
            $this->options['black_list'] = array();
        }
        if (empty($this->options['white_list'])) {
            $this->options['white_list'] = array();
        }
        
        if (is_admin()) {
            add_action('admin_menu', array($this, '__add_options_page'));
            add_action('admin_init', array($this, '__admin_init'));
        }else {
            if ($this->options['effective_on'] == 'the_content') { // 在post和page正文中添加
                add_filter('the_content', array($this, '__add_nofollow'));
            }elseif ($this->options['effective_on'] == 'the_site') { // 全站添加
                add_action('init', array($this, '__init'));
                register_shutdown_function(array($this, '__shutdown'));
            }
        }
    }
    
    function __admin_init()
    {
        register_setting('mg_auto_nofollow_options', 'mg_auto_nofollow', array($this, '__options_validate'));
    }
    
    // 将后台配置页面添加到后台
    function __add_options_page()
    {
        add_options_page(
            '添加Nofollow设置',
            '添加Nofollow设置',
            'administrator',
            __FILE__,
            array($this, '__output_options_page')
        );
    }
    
    // 输出后台配置页面
    function __output_options_page()
    {
        settings_fields('mg_auto_nofollow');
        require_once(MG_AUTO_NOFOLLOW_ABSPATH.'/options.php');
    }
    
    /**
     * 保存后台配置信息
     *
     */
    function __options_validate($options)
    {
        // 作用范围
        if (!empty($options['effective_on']) && $options['effective_on'] == 'the_content') {
            $options['effective_on'] = 'the_content';
        }elseif (!empty($options['effective_on']) && $options['effective_on'] == 'the_site') { // 全站添加
            $options['effective_on'] = 'the_site';
        }else {
            $options['effective_on'] = 'the_content';
        }
        
        // 使用方法
        if (!empty($options['the_way']) && $options['the_way'] == 'rel') {
            $options['the_way'] = 'rel';
        }elseif (!empty($options['the_way']) && $options['the_way'] == 'js') { // 全站添加
            $options['the_way'] = 'js';
        }else {
            $options['the_way'] = 'rel';
        }
        
        // 使用黑白名单
        if (empty($options['use_list'])) {
            $options['use_list'] = 'none';
        }
        
        // 黑名单清理
        if (!empty($options['black_list'])) {
            $options['black_list'] = trim($options['black_list']);
            
            $black_list = array();
            foreach(explode("\n", $options['black_list']) as $value) {
                $black_list[] = trim($value);
            }
            $options['black_list'] = $black_list;
        }else {
            $options['black_list'] = array();
        }
        
        // 白名单清理
        if (!empty($options['white_list'])) {
            $options['white_list'] = trim($options['white_list']);
            
            $white_list = array();
            foreach(explode("\n", $options['white_list']) as $value) {
                $white_list[] = trim($value);
            }
            $options['white_list'] = $white_list;
        }else {
            $options['white_list'] = array();
        }
        
        // 支持我们
        if (empty($options['supportus']['link'])) {
            $options['supportus']['link'] = -1;
        }else {
            $options['supportus']['link'] = 1;
            $this->__link2me();
        }
        
        return $options;
    }
    
    function __init()
    {
        ob_start();
    }
    
    function __shutdown()
    {
        $html  = ob_get_contents();
        ob_end_clean();
        
        echo $this->__add_nofollow($html);
    }
    
    /**
     * 添加nofollow
     *
     */
    function __add_nofollow($content)
    {
        preg_match_all('/<a [^>]+?>/', $content, $matches);
        $labels = & $matches[0];
        
        foreach ($labels as $label) {
            if ($res = $this->__check_conditions($label)) {
                if ($this->options['the_way'] == 'rel') {
                    $new_label = str_replace('>', ' rel="nofollow">', $label);
                }else {
                    $new_label = $this->__set_nofollow_with_js($label);
                }
                $content = str_replace($label, $new_label, $content);
            }
        }
        
        return $content;
    }
    
    /**
     * 检查a标签是否符合添加rel属性的条件
     *
     * 返回true说明符合，否则说明不符合
     *
     */
    function __check_conditions($label)
    {
        // 下面这些条件，只要有一种符合，那么返回false
        return !(
            $this->__if_in_blog($label) ||
            $this->__if_rel_exists($label) ||
            $this->__if_is_bymgcom($label) ||
            $this->__if_in_black($label) ||
            $this->__if_in_white($label)
        );
    }
    
    /**
     * 检查链接地址是不是属于博客的链接地址
     *
     */
    function __if_in_blog($label)
    {
        // 生成当前WP根路径的正则表达式
        $mydomain = get_bloginfo('url');
        $mydomain_pattern = $this->__str2pattern($mydomain);
        
        return preg_match('/href=["\']'.$mydomain_pattern.'/', $label) || // 如果是当前网站域名范围内
               preg_match('/href=["\']\//', $label) || // 如果是使用相对根目录的路径方式
               preg_match('/href=["\']\.{1,2}\//', $label) // 如果是使用相对路径的方式
        ;
    }
    
    /**
     * 检查标签中rel属性是否已经存在
     *
     */
    function __if_rel_exists($label)
    {
        return preg_match('/rel=/', $label);
    }
    
    /**
     * 自私一把，不要对指向bymg.com的链接添加nofollow
     *
     */
    function __if_is_bymgcom($label)
    {
        return preg_match('/\.bymg\./', $label);
    }
    
    /**
     * 是否在白名单中
     *
     */
    function __if_in_white($label)
    {
        if ($this->options['use_list'] != 'white') return false;
        
        foreach ($this->options['white_list'] as $value) {
            $pattern = $this->__str2pattern($value);
            $pattern = "/href=['\"]http:\/\/{$pattern}/";
            if (preg_match($pattern, $label)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 是否 不在 黑名单中
     *
     */
    function __if_in_black($label)
    {
        if ($this->options['use_list'] != 'black') return false;
        
        foreach ($this->options['black_list'] as $value) {
            $pattern = $this->__str2pattern($value);
            $pattern = "/href=['\"]http:\/\/{$pattern}/";
            if (preg_match($pattern, $label)) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 是否在链接的列表中
     *
     */
    function __if_is_link($label)
    {
        
    }
    
    /**
     * 使用js来达到nofollow的目的
     *
     * 目前，某些搜索引擎（如百度）还不支持rel="nofollow"属性
     * 因此要达到目的就需要通过本函数来实现。
     *
     * 本函数的方法，就是将所有需要nofollow的链接地址改为博客地址
     * 然后使用js写回正确地址。
     *
     * @param string $text
     * @return string
     *
     */
    function __set_nofollow_with_js($label)
    {
        preg_match('/ href=[\'"](http:\/\/[^>]+?)[\'"]/i', $label, $matches);
        if (empty($matches[1])) return $label;
        
        $url = $matches[1];
        
        // 如果已经有onfocus事件
        if (preg_match('/ onfocus=/', $label)) {
            $label = preg_replace('/ href=[\'"]http:\/\/[^>]+?[\'"]/i', ' href="/"', $label);
            $label = preg_replace('/( onfocus=\')([^>]+?\')/i', ' $1this.href="'.$url.'";$2', $label);
            $label = preg_replace('/( onfocus=")([^>]+?"]/i', ' $1this.href=\''.$url.'\';$2', $label);
        }
        
        // 如果没有onfocus事件
        else {
            $label = preg_replace('/ href=[\'"]http:\/\/[^>]+?[\'"]/i', ' href="'.get_bloginfo('url').'"', $label);
            $label = str_replace('>', ' onfocus="this.href=\''.$url.'\';">', $label);
        }
        
        return $label;
    }
    
    /**
     * 将文本按照正则表达式的要求转换
     *
     * @param string $text
     * @return string
     *
     */
    function __str2pattern($text)
    {
        // 处理特殊字符
        $text = preg_replace('/([\^\$\(\)\[\]\{\}\*\.\+\?\|\-\/])/i', '\\\$1', $text);
        
        // 处理*号
        $text = str_replace('\*', '.+?', $text);
        
        return $text;
    }
    
    /**
     * 生成一个链接到我们的网站
     *
     */
    function __link2me()
    {
        $linkdata = array(
            'link_name' => 'MG Core Team',
            'link_url' => 'http://www.bymg.com',
            'link_target' => '_blank',
            'link_description' => '提供各种自行开发的中文Wordpress插件和模板',
            'link_rating' => 5,
            //'link_category' => array(1,2),
        );
        
        if (!get_bookmarks(array('search' => $linkdata['link_name']))) {
            wp_insert_link($linkdata);
        }
    }
}

$mg_auto_nofollow = new mgPlugin_AutoNoFollow();
?>
